package sanshui.system.trade.factory.trade.worker.market;

import cn.hutool.core.bean.BeanUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sanshui.system.trade.db.entity.TradeHisOpPos;
import sanshui.system.trade.factory.data.*;
import sanshui.system.trade.factory.trade.TradeSystemContext;
import sanshui.system.trade.factory.trade.strategy.StrategyCallType;
import sanshui.system.trade.factory.trade.strategy.StrategyResult;
import sanshui.system.trade.factory.trade.worker.BackTradeWorker;
import sanshui.system.trade.model.*;
import sanshui.system.trade.util.CommonTimeUtil;
import sanshui.system.trade.util.TradePositionUtil;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * A股回测worker
 * */
public class AGuBackTradeWorker extends BackTradeWorker {
    private static final Logger logger = LoggerFactory.getLogger(AGuBackTradeWorker.class);

    public AGuBackTradeWorker(TradeSysWorkerModel tradeModel, DataCache dataCache) {
        super(tradeModel, dataCache);
    }

    @Override
    protected Bar parseOri2Tick(StockInfoModel stockInfoVo) {
        Bar aGuBar = new Bar();
        aGuBar.setSymbol(stockInfoVo.getTsCode());
        aGuBar.setOpen(stockInfoVo.getOpen());
        aGuBar.setHigh(stockInfoVo.getHigh());
        aGuBar.setLow(stockInfoVo.getLow());
        aGuBar.setClose(stockInfoVo.getClose());
        aGuBar.setTurnover(stockInfoVo.getAmount());
        aGuBar.setTimestamp(stockInfoVo.getTimestamp());
        aGuBar.setVolume(stockInfoVo.getVol());
        return aGuBar;
    }

    /**
     * 使用交易缓存来判断
     * 买入： 必须满足可以按照约定买入
     * 卖出：
     */

    @Override
    protected boolean isValidInThisAccountUseCache(List<StrategyResult> endStrategyCalls) throws Exception {
        boolean isValidBuy = true;
        boolean isValidSell = true;
        long buyNeedTotalMoney = 0L;

        for (StrategyResult endStrategyCall : endStrategyCalls) {
            long needTradeNum = endStrategyCall.getNum();
            long needTradePrice = endStrategyCall.getPrice();
            long fee = endStrategyCall.getFee();
            String code = endStrategyCall.getCode();

            StrategyCallType operationType = endStrategyCall.getStrategyCallType();
            if (StrategyCallType.BUY.compareTo(operationType) == 0) {
                long stockValueSpend = needTradePrice * needTradeNum;
                buyNeedTotalMoney += stockValueSpend + fee;
                logger.info("校验买卖操作与账户余额, code:{}, num:{}, operationType:{}, fee:{}, 需要花费的金额:{}", code, needTradeNum, operationType, fee, stockValueSpend);
            }

            if (StrategyCallType.SELL.compareTo(operationType) == 0) {
                // 计算可交易数量
                Map<String, PositionAccModel> holdPositionMap = tradeSystemContext.getHoldPositionMap();
                PositionAccModel holdPosition = holdPositionMap.getOrDefault(code, new PositionAccModel());

                Long canTradeTarget = holdPosition.getNumCanTrade();
                if (canTradeTarget <= 0) {
                    isValidSell = false;

                }
                if (canTradeTarget.compareTo(needTradeNum) < 0) {
                    isValidSell = true;
                    endStrategyCall.setNum(needTradeNum); // 想卖出数量<实际持有数量，全部卖出
                }
            }
        }
        if (buyNeedTotalMoney > 0){
            Long cashValue = tradeSystemContext.getAccount().getCurrentCash();
            logger.info("共计需要消耗金额：{}, 当前账户现金：{}，是否满足买入:{}", buyNeedTotalMoney, cashValue, cashValue >= buyNeedTotalMoney);
            isValidBuy = cashValue >= buyNeedTotalMoney;
            logger.info("买入是否有效：{}， 卖出是否有效：{}", isValidBuy, isValidSell);
        }
        return isValidBuy && isValidSell;
    }

    @Override
    protected void updateHoldPos(TradeSystemContext tradeSystemContext) {
        logger.info("实时计算[持仓]...");
        // 把当前缓存中的交易信息取出
        List<TradeHisPositionModel> posHisList = tradeSystemContext.getPositionModelList();
        List<TradeHisOpPos> posList = new ArrayList<>();
        for (TradeHisPositionModel model : posHisList) {
            TradeHisOpPos opPos = new TradeHisOpPos();
            BeanUtil.copyProperties(model, opPos);
            posList.add(opPos);
        }
        Map<String, PositionAccModel> hold = TradePositionUtil.parsePosHisToHoldInT1(new HashMap<>(), posList, tradeSystemContext.getTradeTime());
        tradeSystemContext.setHoldPositionMap(hold);
//        tradeSystemContext.setPositionModelList(new ArrayList<>()); // 用完后清空
    }
}
